//
//  PropertyTest.cpp
//  IncrementalAlgorithm
//
//  Created by Roman Kutlak on 10/03/2011.
//  Copyright 2011 Roman Kutlak. All rights reserved.
//

#include <iostream>
#include <sstream>

#include "gtest/gtest.h"

#include "Property.h"
#include "Ontology.h"

using namespace std;
using namespace kutlak::roman::gre;

static Voc& v = Voc::Instance();

#pragma mark -
#pragma mark constructors
// Tests the default c'tor.
TEST(Property, DefaultConstructor) 
{
    // constructor that takes two const char* values
    const Property p;
    
    EXPECT_EQ(p.Attribute(), DEFAULT_ATTRIBUTE);
    EXPECT_EQ(p.Value(), DEFAULT_VALUE);
    EXPECT_EQ(p.Negation(), false);
    EXPECT_EQ(p.Inverse(), false);
    
    Property p2(v.Index("colour"));
    EXPECT_EQ(p2.Attribute(), v.Index("colour"));
    EXPECT_EQ(p2.Value(), DEFAULT_VALUE);
    
    Property p3(DEFAULT_ATTRIBUTE, v.Index("black"));
    EXPECT_EQ(p3.Attribute(), DEFAULT_ATTRIBUTE);
    EXPECT_EQ(p3.Value(), v.Index("black"));
}

// Test the alternative constructor
TEST(Property, AltConstructor) 
{
    Vindex_t att(DEFAULT_ATTRIBUTE);
    Vindex_t val(DEFAULT_VALUE);
    
    // constructor that takes two const string& values
    const Property p(att, val);
    
    EXPECT_EQ(p.Attribute(), DEFAULT_ATTRIBUTE);
    EXPECT_EQ(p.Value(), DEFAULT_VALUE);
    EXPECT_EQ(p.Negation(), false);
    EXPECT_EQ(p.Inverse(), false);
    
    att = v.Index("colour");
    Property p2(att, val);
    EXPECT_EQ(p2.Attribute(), v.Index("colour"));
    EXPECT_EQ(p2.Value(), DEFAULT_VALUE);
    
    att = DEFAULT_ATTRIBUTE;
    val = v.Index("black");
    Property p3(att, val);
    EXPECT_EQ(p3.Attribute(), DEFAULT_ATTRIBUTE);
    EXPECT_EQ(p3.Value(), v.Index("black"));
    
    att = v.Index("colour");    
    Property p4(att);
    EXPECT_EQ(p4.Attribute(), v.Index("colour"));
    EXPECT_EQ(p4.Value(), DEFAULT_VALUE);
}

// Test the copy constructor
TEST(Property, CopyConstructor) 
{
    
    // constructor that takes two const string& values
    Property p("colour", "black");
    
    Property p2(p);
    EXPECT_EQ(p2, p);
    
    p2.SetValue("green");
    Property p3 = p2;
    EXPECT_EQ(p2, p3);
    
    EXPECT_EQ(p3.Attribute(), v.Index("colour"));
    EXPECT_EQ(p3.Value(), v.Index("green"));
}


#pragma mark -
#pragma mark accessors
TEST(Property, Accessors) 
{
    Property p;
    
    EXPECT_EQ(p.Attribute(), DEFAULT_ATTRIBUTE);
    EXPECT_EQ(p.Value(), DEFAULT_VALUE);
    EXPECT_EQ(p.Negation(), false);
    EXPECT_EQ(p.Inverse(), false);
    
    p.SetAttribute(v.Index("colour"));
    p.SetValue(v.Index("black"));
    
    EXPECT_EQ(p.Attribute(), v.Index("colour"));
    EXPECT_EQ(p.Value(), v.Index("black"));
    
    p.SetNegation(true);
    p.SetInverse(true);
    EXPECT_EQ(p.Negation(), true);
    EXPECT_EQ(p.Inverse(), true);
}


#pragma mark -
#pragma mark operators
TEST(Property, Operators) 
{
    Property p, p2;
    EXPECT_EQ(p, p2);
    
    p.SetAttribute("size");
    EXPECT_NE(p, p2);
    
    p2.SetAttribute("size");
    EXPECT_EQ(p, p2);
    
    p.SetValue("large");
    p.SetNegation(true);
    p.SetInverse(true);
    p2 = p;
    EXPECT_EQ(p, p2);

}


#pragma mark -
#pragma mark IO
TEST(Property, IO) 
{
    stringstream str("<hairColour> <lightBrown>");
    Property p("hairColour", "lightBrown");
    
    Property p2;
    p2.FromRdf(str);
    EXPECT_EQ(p, p2);
    
    Property p3("colour", "black");
    stringstream s;
    s << "<colour> <black>";
    stringstream strm;
    p3.ToRdf(strm);
    EXPECT_EQ(s.str(), strm.str());
    
    string pRdf = p3.ToRdf();
    EXPECT_EQ(pRdf, s.str());
    
    string pStr = p3.ToString();
    EXPECT_EQ("Property colour black", pStr);
    
    Property def;
    EXPECT_EQ("Property No Attribute No Value", def.ToString());
    def.SetNegation(true);
    EXPECT_EQ("Property NEG No Attribute No Value", def.ToString());
    def.SetInverse(true);
    EXPECT_EQ("Property NEG INV No Attribute No Value", def.ToString());
}

TEST(Property, Serialisation) 
{
    stringstream ss;
    
    Property p = Ontology::kPersonType;
    Vindex_t type = Ontology::kType;
    Vindex_t person = Ontology::kPerson;
    
    stringstream ss2;
    ss2 << "<p> ";
    ss2 << type << " " << person << ' ';
    ss2 << false << " " << false << ' ';
    ss2 << "</p>\n";
    
    ss << p;
    
    EXPECT_EQ(ss2.str(), ss.str());
    
    Property q = p;
    Property r = p;
    EXPECT_EQ(p, q);
    
    stringstream ss3;
    ss3 << "<p> mallformed </p>";
    
    try 
    {
        ss3 >> q;
    } 
    catch (DeserialisationException& de) 
    {
        cerr << de.what() << "\n\t" << de.data() << endl;
    }
    
    EXPECT_EQ(q, r);
    
    try 
    {
        ss >> q;
    } 
    catch (DeserialisationException& e) 
    {
        cerr << e.what() << "\n\t" << e.data() << endl;
    }
    
    EXPECT_EQ(p, q);
    
    
    ss.str("");
    ss << Ontology::kThingType << Ontology::kPersonType;
    
    try 
    {
        Property p1, p2;
        ss >> p1 >> p2;
        
        EXPECT_EQ(p1, Ontology::kThingType);
        EXPECT_EQ(p2, Ontology::kPersonType);
    } 
    catch (DeserialisationException& e) 
    {
        cerr << e.what() << "\n\t" << e.data() << endl;
    }
}
